package com.park.microprofile.config;

import com.park.microprofile.configsource.ConfigSources;
import com.park.microprofile.configvalue.DefaultConfigValue;
import com.park.microprofile.converter.Converters;
import com.park.microprofile.converter.PrioritizedConverter;
import org.eclipse.microprofile.config.Config;
import org.eclipse.microprofile.config.ConfigValue;
import org.eclipse.microprofile.config.spi.ConfigSource;
import org.eclipse.microprofile.config.spi.Converter;

import java.nio.file.OpenOption;
import java.util.*;

import static java.util.stream.StreamSupport.stream;

/**
 * 配置实现类
 *
 * @author Aaron
 * @date 2021/7/13 11:12
 */
public class DefaultConfig implements Config {
    /**
     * 配置源集合
     */
    private final ConfigSources configSources;
    /**
     * 类型转换器集合
     */
    private final Converters converters;

    public DefaultConfig(ConfigSources configSources, Converters converters) {
        this.configSources = configSources;
        this.converters = converters;
    }

    @Override
    public <T> T getValue(String propertyName, Class<T> propertyType) {
        ConfigValue configValue = getConfigValue(propertyName);
        if (configValue == null) {
            return null;
        }
        String propertyValue = configValue.getValue();

        // String 转换成目标类型
        Optional<Converter<T>> converter = this.getConverter(propertyType);

        return converter.map(tConverter -> tConverter.convert(propertyValue)).orElse(null);
    }

    @Override
    public ConfigValue getConfigValue(String propertyName) {
        Iterator<ConfigSource> iterator = configSources.iterator();

        ConfigSource configSource = null;

        while (iterator.hasNext()) {
            configSource = iterator.next();
            String value = configSource.getValue(propertyName);
            if (value != null) {
                break;
            }
        }

        if (configSource == null) {
            return null;
        }

        return new DefaultConfigValue(propertyName
                , configSource.getValue(propertyName)
                , configSource.getValue(propertyName)
                , configSource.getName()
                , configSource.getOrdinal());
    }

    @Override
    public <T> Optional<T> getOptionalValue(String propertyName, Class<T> propertyType) {
        T value = this.getValue(propertyName, propertyType);
        if (value == null) {
            return Optional.empty();
        }
        return Optional.of(value);
    }

    @Override
    public Iterable<String> getPropertyNames() {
        return stream(configSources.spliterator(), false)
                .map(ConfigSource::getPropertyNames)
                .collect(LinkedHashSet::new, Set::addAll, Set::addAll);
    }

    @Override
    public Iterable<ConfigSource> getConfigSources() {
        return configSources;
    }

    @Override
    public <T> Optional<Converter<T>> getConverter(Class<T> forType) {
        PriorityQueue<PrioritizedConverter<?>> converterQueue = this.converters.getConverter(forType);
        PrioritizedConverter<?> peek = converterQueue.peek();
        if (peek == null) {
            return Optional.empty();
        }
        Converter<T> converter = (Converter<T>) peek.getConverter();
        return Optional.of(converter);
    }

    @Override
    public <T> T unwrap(Class<T> type) {
        return null;
    }

}
